package main

import (
	"fmt"
	. "go_data_structures_and_algorithms/tool"
)

/*
题目描述：
请你仅使用两个队列实现一个后入先出（LIFO）的栈，并支持普通栈的全部四种操作（push、top、pop 和 empty）。

实现 MyStack 类：

void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的，返回 true ；否则，返回 false 。

思路:
创建两个栈 没取元素之前依次向第一个栈里面压入元素
之后再由第一个栈往第二个栈里面转存数据，剩最后一个留着，
再提出这个数据就是队列先进先出的数据了

我写的这个是判断哪个stack为空另一个stack就是保存数据的
所以push和pop就针对这一个特性进行操作
peek方法稍微有点不同就是类似于pop方法执行完后返回那个值后再把他加入stack当中

左神的办法是实时交换两个指针，时刻保持主stack是数据的保存栈
这样可以显著地缩减代码是一种实现的不同大体上都一样
*/
func main() {
	stack := NewQueueImplementationStack()
	stack.Push(1)
	stack.Push(2)
	stack.Push(3)
	stack.Push(4)
	stack.Push(5)
	fmt.Println(stack.Pop(), stack.Pop(), stack.Peek(), stack.Pop(), stack.Pop(), stack.Pop())
}

type QueueImplementationStack struct {
	Stack1 MyQueue[int]
	Stack2 MyQueue[int]
}

func NewQueueImplementationStack() *QueueImplementationStack {

	return &QueueImplementationStack{
		Stack1: MyQueue[int]{},
		Stack2: MyQueue[int]{},
	}
}

func (q *QueueImplementationStack) Push(v int) {

	if q.IsEmpty() {
		q.Stack1.Offer(v)
	} else if q.Stack1.IsEmpty() {
		q.Stack2.Offer(v)
	} else if q.Stack2.IsEmpty() {
		q.Stack1.Offer(v)
	}
}
func (q *QueueImplementationStack) Pop() int {
	if q.IsEmpty() {
		fmt.Println("没有数据可以弹出")
	} else if q.Stack1.IsEmpty() {
		for q.Stack2.Size != 1 {
			q.Stack1.Offer(q.Stack2.Poll())
		}
		return q.Stack2.Poll()
	} else if q.Stack2.IsEmpty() {
		for q.Stack1.Size != 1 {
			q.Stack2.Offer(q.Stack1.Poll())
		}
		return q.Stack1.Poll()
	}

	return -1
}

func (q *QueueImplementationStack) Peek() int {
	if q.IsEmpty() {
		fmt.Println("没有数据可以弹出")
	} else if q.Stack1.IsEmpty() {
		for q.Stack2.Size != 1 {
			q.Stack1.Offer(q.Stack2.Poll())
		}
		res := q.Stack2.Poll()
		q.Stack1.Offer(res)
		return res
	} else if q.Stack2.IsEmpty() {
		for q.Stack1.Size != 1 {
			q.Stack2.Offer(q.Stack1.Poll())
		}
		res := q.Stack1.Poll()
		q.Stack2.Offer(res)
		return res
	}

	return -1
}

func (q *QueueImplementationStack) IsEmpty() bool {

	return q.Stack1.IsEmpty() && q.Stack2.IsEmpty()
}
